/**
 * <copyright>
 * </copyright>
 *
 * $Id$
 */
package BoardGame.impl;

import BoardGame.Board;
import BoardGame.BoardGameFactory;
import BoardGame.BoardGamePackage;
import BoardGame.Field;
import BoardGame.Figure;

import de.upb.tools.fca.*;

import de.upb.tools.sdm.*;

import java.lang.reflect.InvocationTargetException;

import java.util.*;

import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.NotificationChain;

import org.eclipse.emf.common.util.EList;

import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.InternalEObject;

import org.eclipse.emf.ecore.impl.ENotificationImpl;
import org.eclipse.emf.ecore.impl.EObjectImpl;

import org.eclipse.emf.ecore.util.EObjectContainmentWithInverseEList;
import org.eclipse.emf.ecore.util.InternalEList;

/**
 * <!-- begin-user-doc -->
 * An implementation of the model object '<em><b>Board</b></em>'.
 * <!-- end-user-doc -->
 * <p>
 * The following features are implemented:
 * <ul>
 *   <li>{@link BoardGame.impl.BoardImpl#getFields <em>Fields</em>}</li>
 *   <li>{@link BoardGame.impl.BoardImpl#getSelectedFigure <em>Selected Figure</em>}</li>
 *   <li>{@link BoardGame.impl.BoardImpl#getWidth <em>Width</em>}</li>
 *   <li>{@link BoardGame.impl.BoardImpl#getHeight <em>Height</em>}</li>
 * </ul>
 * </p>
 *
 * @generated
 */
public class BoardImpl extends EObjectImpl implements Board {
	/**
	 * The cached value of the '{@link #getFields() <em>Fields</em>}' containment reference list.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getFields()
	 * @generated
	 * @ordered
	 */
	protected EList<Field> fields;

	/**
	 * The cached value of the '{@link #getSelectedFigure() <em>Selected Figure</em>}' reference.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getSelectedFigure()
	 * @generated
	 * @ordered
	 */
	protected Figure selectedFigure;

	/**
	 * The default value of the '{@link #getWidth() <em>Width</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getWidth()
	 * @generated
	 * @ordered
	 */
	protected static final int WIDTH_EDEFAULT = 0;

	/**
	 * The cached value of the '{@link #getWidth() <em>Width</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getWidth()
	 * @generated
	 * @ordered
	 */
	protected int width = WIDTH_EDEFAULT;

	/**
	 * The default value of the '{@link #getHeight() <em>Height</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getHeight()
	 * @generated
	 * @ordered
	 */
	protected static final int HEIGHT_EDEFAULT = 0;

	/**
	 * The cached value of the '{@link #getHeight() <em>Height</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getHeight()
	 * @generated
	 * @ordered
	 */
	protected int height = HEIGHT_EDEFAULT;

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	protected BoardImpl() {
		super();
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	protected EClass eStaticClass() {
		return BoardGamePackage.Literals.BOARD;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public EList<Field> getFields() {
		if (fields == null) {
			fields = new EObjectContainmentWithInverseEList<Field>(Field.class,
					this, BoardGamePackage.BOARD__FIELDS,
					BoardGamePackage.FIELD__BOARD);
		}
		return fields;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public Figure getSelectedFigure() {
		if (selectedFigure != null && selectedFigure.eIsProxy()) {
			InternalEObject oldSelectedFigure = (InternalEObject) selectedFigure;
			selectedFigure = (Figure) eResolveProxy(oldSelectedFigure);
			if (selectedFigure != oldSelectedFigure) {
				if (eNotificationRequired())
					eNotify(new ENotificationImpl(this, Notification.RESOLVE,
							BoardGamePackage.BOARD__SELECTED_FIGURE,
							oldSelectedFigure, selectedFigure));
			}
		}
		return selectedFigure;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public Figure basicGetSelectedFigure() {
		return selectedFigure;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setSelectedFigure(Figure newSelectedFigure) {
		Figure oldSelectedFigure = selectedFigure;
		selectedFigure = newSelectedFigure;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET,
					BoardGamePackage.BOARD__SELECTED_FIGURE, oldSelectedFigure,
					selectedFigure));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public int getWidth() {
		return width;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setWidth(int newWidth) {
		int oldWidth = width;
		width = newWidth;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET,
					BoardGamePackage.BOARD__WIDTH, oldWidth, width));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public int getHeight() {
		return height;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setHeight(int newHeight) {
		int oldHeight = height;
		height = newHeight;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET,
					BoardGamePackage.BOARD__HEIGHT, oldHeight, height));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void initialize(int w, int h) {
		boolean fujaba__Success = false;
		Iterator fujaba__IterThisToLeftField = null;
		Field leftField = null;
		Iterator fujaba__IterThisToUpField = null;
		Field upField = null;
		Field field = null;

		do {
			while (true) {
				// story pattern create field
				try {
					fujaba__Success = false;

					// attribute condition
					JavaSDM.ensure(this.getHeight() < h);

					// iterate to-many link fields from this to leftField
					fujaba__Success = false;

					fujaba__IterThisToLeftField = this.getFields().iterator();

					while (!(fujaba__Success)
							&& fujaba__IterThisToLeftField.hasNext()) {
						try {
							leftField = (Field) fujaba__IterThisToLeftField
									.next();

							// check optional
							if (leftField != null) {
								// attribute condition
								JavaSDM.ensure(leftField.getX() == width - 1);

								// attribute condition
								JavaSDM.ensure(leftField.getY() == this
										.getHeight());

							}
							fujaba__Success = true;
						} catch (JavaSDMException fujaba__InternalException) {
							fujaba__Success = false;
						}
					}
					if (!fujaba__Success) {
						fujaba__Success = true;
						leftField = null;
					}
					// iterate to-many link fields from this to upField
					fujaba__Success = false;

					fujaba__IterThisToUpField = this.getFields().iterator();

					while (!(fujaba__Success)
							&& fujaba__IterThisToUpField.hasNext()) {
						try {
							upField = (Field) fujaba__IterThisToUpField.next();

							// check optional
							if (upField != null) {
								// attribute condition
								JavaSDM.ensure(upField.getX() == this
										.getWidth());

								// attribute condition
								JavaSDM.ensure(upField.getY() == height - 1);

							}
							fujaba__Success = true;
						} catch (JavaSDMException fujaba__InternalException) {
							fujaba__Success = false;
						}
					}
					if (!fujaba__Success) {
						fujaba__Success = true;
						upField = null;
					}
					// create object field
					field = BoardGameFactory.eINSTANCE.createField();
					// assign attribute field
					field.setX(this.getWidth());
					// assign attribute field
					field.setY(this.getHeight());
					// create link
					field.setBoard(this);

					// check optional
					if (leftField != null) {
						// create link
						leftField.setNeighbourEast(field);

					}// check optional
					if (upField != null) {
						// create link
						upField.setNeighbourSouth(field);

					}
					fujaba__Success = true;
				} catch (JavaSDMException fujaba__InternalException) {
					fujaba__Success = false;
				}

				if (!fujaba__Success) {
					break;
				}
				// story pattern move on to next row
				try {
					fujaba__Success = false;

					// assign attribute this
					this.setHeight(this.height + 1);
					fujaba__Success = true;
				} catch (JavaSDMException fujaba__InternalException) {
					fujaba__Success = false;
				}

			}
			// story pattern move on to next column
			try {
				fujaba__Success = false;

				// assign attribute this
				this.setWidth(this.width + 1);
				fujaba__Success = true;
			} catch (JavaSDMException fujaba__InternalException) {
				fujaba__Success = false;
			}

			// story pattern if width is in range, reset height
			try {
				fujaba__Success = false;

				// attribute condition
				JavaSDM.ensure(this.getWidth() < w);

				// assign attribute this
				this.setHeight(0);
				fujaba__Success = true;
			} catch (JavaSDMException fujaba__InternalException) {
				fujaba__Success = false;
			}

		} while (fujaba__Success);
		return;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void pressed(Field field) {
		boolean fujaba__Success = false;
		Figure selFigure = null;
		Figure toBeSelFigure = null;

		// story pattern isSelected
		try {
			fujaba__Success = false;

			// bind object
			selFigure = this.getSelectedFigure();

			// check object selFigure is really bound
			JavaSDM.ensure(selFigure != null);

			// destroy link
			org.moflon.util.eMoflonEMFUtil.removeOppositeReference(this,
					selFigure, "selectedFigure");
			fujaba__Success = true;
		} catch (JavaSDMException fujaba__InternalException) {
			fujaba__Success = false;
		}

		if (fujaba__Success) {
			selFigure.moveTo(field);

		} else {
			// story pattern noFigureSelected
			try {
				fujaba__Success = false;

				// check object field is really bound
				JavaSDM.ensure(field != null);
				// bind object
				toBeSelFigure = field.getFigure();

				// check object toBeSelFigure is really bound
				JavaSDM.ensure(toBeSelFigure != null);

				// create link
				this.setSelectedFigure(toBeSelFigure);

				fujaba__Success = true;
			} catch (JavaSDMException fujaba__InternalException) {
				fujaba__Success = false;
			}

		}
		return;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public Field getUpperLeftField() {
		boolean fujaba__Success = false;
		Field north = null;
		Field west = null;
		Iterator fujaba__IterThisToField = null;
		Field field = null;

		// story pattern determine field with neither northern nor western neighbour
		try {
			fujaba__Success = false;

			// iterate to-many link fields from this to field
			fujaba__Success = false;

			fujaba__IterThisToField = this.getFields().iterator();

			while (!(fujaba__Success) && fujaba__IterThisToField.hasNext()) {
				try {
					field = (Field) fujaba__IterThisToField.next();

					// check object field is really bound
					JavaSDM.ensure(field != null);
					// check negative bindings
					try {
						fujaba__Success = false;

						// bind object
						north = field.getNeighbourNorth();

						// check object north is really bound
						JavaSDM.ensure(north != null);

						// check isomorphic binding between objects north and field
						JavaSDM.ensure(!north.equals(field));

						fujaba__Success = true;
					} catch (JavaSDMException fujaba__InternalException) {
						fujaba__Success = false;
					}

					fujaba__Success = !(fujaba__Success);

					JavaSDM.ensure(fujaba__Success);

					// check negative bindings
					try {
						fujaba__Success = false;

						// bind object
						west = field.getNeighbourWest();

						// check object west is really bound
						JavaSDM.ensure(west != null);

						// check isomorphic binding between objects west and field
						JavaSDM.ensure(!west.equals(field));

						fujaba__Success = true;
					} catch (JavaSDMException fujaba__InternalException) {
						fujaba__Success = false;
					}

					fujaba__Success = !(fujaba__Success);

					JavaSDM.ensure(fujaba__Success);

					fujaba__Success = true;
				} catch (JavaSDMException fujaba__InternalException) {
					fujaba__Success = false;
				}
			}
			JavaSDM.ensure(fujaba__Success);
			fujaba__Success = true;
		} catch (JavaSDMException fujaba__InternalException) {
			fujaba__Success = false;
		}

		return field;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@SuppressWarnings("unchecked")
	@Override
	public NotificationChain eInverseAdd(InternalEObject otherEnd,
			int featureID, NotificationChain msgs) {
		switch (featureID) {
		case BoardGamePackage.BOARD__FIELDS:
			return ((InternalEList<InternalEObject>) (InternalEList<?>) getFields())
					.basicAdd(otherEnd, msgs);
		}
		return super.eInverseAdd(otherEnd, featureID, msgs);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public NotificationChain eInverseRemove(InternalEObject otherEnd,
			int featureID, NotificationChain msgs) {
		switch (featureID) {
		case BoardGamePackage.BOARD__FIELDS:
			return ((InternalEList<?>) getFields()).basicRemove(otherEnd, msgs);
		}
		return super.eInverseRemove(otherEnd, featureID, msgs);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public Object eGet(int featureID, boolean resolve, boolean coreType) {
		switch (featureID) {
		case BoardGamePackage.BOARD__FIELDS:
			return getFields();
		case BoardGamePackage.BOARD__SELECTED_FIGURE:
			if (resolve)
				return getSelectedFigure();
			return basicGetSelectedFigure();
		case BoardGamePackage.BOARD__WIDTH:
			return getWidth();
		case BoardGamePackage.BOARD__HEIGHT:
			return getHeight();
		}
		return super.eGet(featureID, resolve, coreType);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void eSet(int featureID, Object newValue) {
		switch (featureID) {
		case BoardGamePackage.BOARD__FIELDS:
			getFields().clear();
			getFields().addAll((Collection<? extends Field>) newValue);
			return;
		case BoardGamePackage.BOARD__SELECTED_FIGURE:
			setSelectedFigure((Figure) newValue);
			return;
		case BoardGamePackage.BOARD__WIDTH:
			setWidth((Integer) newValue);
			return;
		case BoardGamePackage.BOARD__HEIGHT:
			setHeight((Integer) newValue);
			return;
		}
		super.eSet(featureID, newValue);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public void eUnset(int featureID) {
		switch (featureID) {
		case BoardGamePackage.BOARD__FIELDS:
			getFields().clear();
			return;
		case BoardGamePackage.BOARD__SELECTED_FIGURE:
			setSelectedFigure((Figure) null);
			return;
		case BoardGamePackage.BOARD__WIDTH:
			setWidth(WIDTH_EDEFAULT);
			return;
		case BoardGamePackage.BOARD__HEIGHT:
			setHeight(HEIGHT_EDEFAULT);
			return;
		}
		super.eUnset(featureID);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public boolean eIsSet(int featureID) {
		switch (featureID) {
		case BoardGamePackage.BOARD__FIELDS:
			return fields != null && !fields.isEmpty();
		case BoardGamePackage.BOARD__SELECTED_FIGURE:
			return selectedFigure != null;
		case BoardGamePackage.BOARD__WIDTH:
			return width != WIDTH_EDEFAULT;
		case BoardGamePackage.BOARD__HEIGHT:
			return height != HEIGHT_EDEFAULT;
		}
		return super.eIsSet(featureID);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public Object eInvoke(int operationID, EList<?> arguments)
			throws InvocationTargetException {
		switch (operationID) {
		case BoardGamePackage.BOARD___INITIALIZE__INT_INT:
			initialize((Integer) arguments.get(0), (Integer) arguments.get(1));
			return null;
		case BoardGamePackage.BOARD___PRESSED__FIELD:
			pressed((Field) arguments.get(0));
			return null;
		case BoardGamePackage.BOARD___GET_UPPER_LEFT_FIELD:
			return getUpperLeftField();
		}
		return super.eInvoke(operationID, arguments);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public String toString() {
		if (eIsProxy())
			return super.toString();

		StringBuffer result = new StringBuffer(super.toString());
		result.append(" (width: ");
		result.append(width);
		result.append(", height: ");
		result.append(height);
		result.append(')');
		return result.toString();
	}

} //BoardImpl
